var iframeHtml =
'<?xml version="1.0" encoding="utf-8" ?>'
+'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
+'<html>'
+'<head>'
+'<meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
+'</head>'
+'<body id="ifbody" OnKeyPress="alert(\'key pressed \'+event.keyCode);if(event.keyCode==13)'
+'{event.keyCode=182;var keyEvent=this.ownerDocument.createEventObject( event );keyEvent.button = 7;this.fireEvent( \'onmousedown\',keyEvent );};'
+'return true;">'
+'<span>Initial text</span></body>'
+'</html>';

function avoidEnter( event )
{
  alert('2')
  if(event.keyCode==13)
    event.keyCode=54;
  return true;
}

var CMEFrame = Class.create();
CMEFrame.prototype =
{
  initialize: function( wrapperId, id )
  {
    this.wrapper = $( wrapperId );
    this.iframe = Element.extend( this.wrapper.ownerDocument.createElement( 'iframe' ) ); 
    this.iframe.src='javascript:void(0)';
    this.iframe.frameBorder = 0;
    this.iframe.width = '100%';
    this.iframe.height = '100%';
    this.iframe.id = id;
    this.wrapper.appendChild( this.iframe );
    this.doc = this.iframe.contentWindow.document;
    this.doc.open();
    this.doc.write( iframeHtml );
    this.doc.close();
    Event.observe( this.doc, 'contextmenu', this.stub.bindAsEventListener( this ), true );        // IE needs it
    Event.observe( this.doc, 'mousedown', this.doOnMouseDown.bindAsEventListener( this ), true );
    Event.observe( this.doc, 'keypress', this.doOnKeyDown.bindAsEventListener( this ), true );
    this.range = new CRange( this.iframe.contentWindow );
    this.cmenu = globalContextMenu;
    this.palette = globalPalette;
    this.editable = false;
    this.htmlMode = false;
    this.url = '/wcme/engine';
    this.saveBorderStyle = new Hash();
  },
  
  setEditable: function()
  {
    this.editable = true;
//    this.doc.body.bgColor = '#FEFEF8'
    this.saveBorderStyle['border-width'] = this.wrapper.getStyle('border-width');
    this.saveBorderStyle['border-style'] = this.wrapper.getStyle('border-style');
    this.saveBorderStyle['border-color'] = this.wrapper.getStyle('border-color');
    this.wrapper.style.border = '3px double green';

    var docm = this.doc
    Try.these
    (
      function(){ docm.createRange(); docm.designMode = 'on' },  // FF
      function(){ docm.body.createTextRange(); docm.body.contentEditable = true }   // IE
    );
    this.palette.activate( this );
    if( this.htmlMode )
      this.palette.hide();
  },
  
  unsetEditable: function()
  {
    this.editable = false;
//    this.doc.body.bgColor = '#FFFFFF'
    this.wrapper.setStyle( this.saveBorderStyle );

    var docm = this.doc
    Try.these
    (
      function(){ docm.createRange(); docm.designMode = 'off' },  // FF
      function(){ docm.body.createTextRange(); docm.body.contentEditable = false }   // IE
    );
    this.palette.deactivate();
  },
  
  load: function()
  {
//    alert('>>> load');
    new MyAjaxUpdater( this, this.url,
    {
      method: 'get',
      parameters: 
      {
        operation: 'load',
        id: this.iframe.id
      },
      onFailure: function( transport )
      {
        alert('onFailure status= ' + transport.status + ' url=' + this.url );
      }
    });
//    alert('<<< load');
  },
  
  save: function()
  {
    ajaxReq = new Ajax.Request( this.url, 
    {
      method: 'post',
      parameters: 
      {
        operation: 'save',
        content: this.doc.body.innerHTML,
        id: this.iframe.id
      },
    
      onSuccess: function( transport ) 
      {
        alert('Response : ' + transport.responseText );
      },
    
      onFailure: function( transport )
      {
        alert('onFailure status= ' + transport.status + ' url=' + ajaxReq.url );
      }
    });
  },
  
  doOnMouseDown: function( event )
  {
    if( ! Event.isLeftClick( event ) )
    {
      if( event.button == 7 )
      {
        alert('mouse down with 7')
        setTimeout( 'if(globalPalette.cmeFrame)globalPalette.cmeFrame.refresh();',100);
      }  
      else
      {
        this.cmenu.setMode( this.editable );
        this.cmenu.show( this );
        var pos = Position.cumulativeOffset( this.iframe );
//      var pos = Position.realOffset( this.iframe );
        this.cmenu.menu.style.left = pos[0] + Event.pointerX(event) + "px"
        this.cmenu.menu.style.top = pos[1] + Event.pointerY(event) + "px"
      }
      Event.stop( event );
      return false;
    }
    return true;
  },
  
  doOnKeyDown: function( event )
  {
    var keyCode = Try.these
    (
      function(){ return event.keyCode },   // IE (FF)
      function(){ return event.charCode }   // FF
    ) || -1;
    
//    alert('key down = ' + keyCode + ' type = {' + event.type + '}' )
    if( keyCode == 13 ) // <Enter>
    {
      var ifdoc = this.doc, retCode = true;
      alert('Enter key down = ' + keyCode + ' type = {' + event.type + '}' )
      Try.these
      (
        function()   // FF
        { 
          var keyEvent = ifdoc.createEvent( "KeyboardEvent" );
          keyEvent.initKeyEvent(                                                      
            "keypress",       //  in DOMString typeArg,                                                           
            true,             //  in boolean canBubbleArg,                                                        
            true,             //  in boolean cancelableArg,                                                       
            null,             //  in nsIDOMAbstractView viewArg,  Specifies UIEvent.view. This value may be null.     
            false,            //  in boolean ctrlKeyArg,                                                               
            false,            //  in boolean altKeyArg,                                                        
            false,            //  in boolean shiftKeyArg,                                                      
            false,            //  in boolean metaKeyArg,                                                       
            182,              //  in unsigned long keyCodeArg,                                                      
            182);             //  in unsigned long charCodeArg)
          ifdoc.body.dispatchEvent( keyEvent );
          Event.stop( event );
          retCode = false;
        },
        function()   // IE
        { 
//          var keyEvent = ifdoc.createEventObject( event );
//          keyEvent.keyCode = 183;
//          keyEvent.button = 7;
//          ifdoc.body.fireEvent( 'onmousedown',keyEvent );
// alert('after fire event = ' + keyEvent.type + ' ' + keyEvent.keyCode )
        }
      ); 
//      Event.stop( event );
//      return false;
      return retCode;
    }
    else
    if( keyCode == 182 ) // <Enter>
    {
      var ifdoc = this.doc, ifwin = this.iframe.contentWindow;
      alert( 'Enter key down = ' + keyCode + ' type = {' + event.type + '}' )
      Try.these
      (
        function()   // FF
        { 
          var keyEvent = ifdoc.createEvent( "MouseEvents" );
          keyEvent.initMouseEvent(                                                      
            "mousedown",//  the string to set the event's type to. Possible types for mouse events include: click, mousedown, mouseup, mouseover, mousemove, mouseout,                                                           
            true,      //  whether or not the event can bubble. Sets the value of event.bubbles,                                                        
            true,      //  whether or not the event's default action can be prevented. Sets the value of event.cancelable,                                                       
            ifwin,     //  the Event's AbstractView. You should pass the window object here. Sets the value of event.view.     
            0,         //  the Event's mouse click count. Sets the value of event.detail,                                                               
            0,         //  the Event's screen x coordinate. Sets the value of event.screenX,                                                        
            0,         //  the Event's screen y coordinate. Sets the value of event.screenY,                                                      
            0,         //  the Event's client x coordinate. Sets the value of event.clientX,                                                       
            0,         //  the Event's client y coordinate. Sets the value of event.clientY,                                                      
            false,     //  whether or not control key was depressed during the Event. Sets the value of event.ctrlKey,                                                      
            false,     //  whether or not alt key was depressed during the Event. Sets the value of event.altKey                                                      
            false,     //  whether or not shift key was depressed during the Event. Sets the value of event.shiftKey                                                      
            false,     //  whether or not meta key was depressed during the Event. Sets the value of event.metaKey                                                      
            7,         //  the Event's mouse event.button.                                                      
            null);     //  the Event's related EventTarget. Only used with some event types (e.g. mouseover and mouseout). In other cases, pass null.)
          ifdoc.body.dispatchEvent( keyEvent );
        },
        function()   // IE
        { 
        }
      ); 
    }
    return true;    
  },
  
  switchToHTML: function()
  {
    var html = this.doc.body.innerHTML;
    this.doc.body.innerHTML = '';
    this.doc.body.appendChild( this.doc.createTextNode( html ) );
    if( this.editable )
       this.palette.hide();
    this.htmlMode = true;
  },
  
  switchToRichText: function()
  {
    var rText = '';//this.doc.body.firstChild.nodeValue;
    var node = this.doc.body.firstChild;
    while( node != null )
    {
      if( node.nodeType == 3 )
        rText += node.nodeValue;
      node = node.nextSibling;  
    }
    this.doc.body.innerHTML = rText;
    if( this.editable )
      this.palette.show();
    this.htmlMode = false;
  },
  
  refresh: function()
  {
    if( ! this.htmlMode )
    {
      var html = this.doc.body.innerHTML;
      html = html.gsub( String.fromCharCode(182), '<br/>');
      this.doc.body.innerHTML = html;
    }
    else
    {
      var html = this.doc.body.innerHTML;
      html = html.gsub( String.fromCharCode(182), '<br/>');
      this.doc.body.innerHTML = html;
/*      var node = this.doc.body.firstChild;
      while( node != null )
      {
        if( node.nodeType == 3 )
        {
          var ntext = node.nodeValue;
          ntext = ntext.gsub( String.fromCharCode(182), '\n');
          node.nodeValue = ntext;
        }  
        node = node.nextSibling;  
      }*/
    }
  },
  
  stub: function( event )
  {
      Event.stop( event );
      return false;
  }
  
}

var MyAjaxUpdater = Class.create();

Object.extend( Object.extend( MyAjaxUpdater.prototype, Ajax.Request.prototype ), 
{
  initialize: function( container, url, options ) 
  {
    this.element = container.doc.body;
    this.transport = Ajax.getTransport();
    this.setOptions( options );
    this.options.onSuccess = (function(transport, param) {
      this.updateContent();
    }).bind(this);

    this.request(url);
  },
  
  updateContent: function() 
  {
    this.element.innerHTML = this.transport.responseText;
  }
});

var ContextMenu = Class.create();

ContextMenu.prototype = //Object.extend( new Element(),
{
  initialize: function()
  {
    var docm = document;
    var element = Element.extend( docm.createElement( 'div' ) );
    docm.body.appendChild( element );
    element.className = 'contextMenu';  
    element.id = 'context_menu'
    this.items = new Array()
    var menu = [
//      item        hover       handler     id
      ['Edit','make area editable',0]   /*  Edit item   */
     ,['Save','save area content',1]    /*  Save item   */
     ,['Quit','quit from edit mode',2]  /*  Quit item   */
     ,['Html/Rich text','switch between html and rich text',4]       /*  Switch html/rich text */
     ,['Cancel','cancel changes',3]     /*  Cancel item */
    ]
    
    for( var i = 0; i < menu.length; i++ )
    {
      var div = Element.extend( docm.createElement( 'div' ) );
      var a = Element.extend( docm.createElement( 'a' ) );
      a.href = 'javascript:void(0)'
      a.title = menu[i][1];
      a.innerHTML = menu[i][0];
      Event.observe( a, 'click', this.doOnClick.bindAsEventListener( this, menu[i][2] ) );
      div.appendChild( a );
      element.appendChild( div );
//      this.items.push( a );
      this.items[ menu[i][2] ] = a;
    }

    this.menu = element;
    this.target = null;
  },
  
  doOnClick: function( event, i )
  {
//    alert( i + '; L=' + arguments.length + '; arg[0]=' + arguments[0]+ '; arg[1]=' + arguments[1] + '; arg[2]=' + arguments[2] )
    switch( i )
    {
      case 0:
        if( this.target )
        {
          if( this.prev != null && this.prev != this.target )
            this.prev.unsetEditable();
          this.target.setEditable();
        }
        this.hide();
        break;
      case 1:
        if( this.target )
        {
          this.target.save();
        }  
        this.hide();
        break;  
      case 2:
        if( this.target )
        {
          this.target.unsetEditable();
        }
        this.hide();
        break;  
      case 3:
        if( this.target )
        {
          this.target.unsetEditable();
          this.target.load();  // TO DO check dirty flag !!!
        }
        this.hide();
        break;  
      case 4:
        if( this.target )
        {
          if( this.target.htmlMode )
            this.target.switchToRichText();
          else
            this.target.switchToHTML();
        }
        this.hide();
        break;  
      default:
        break;
    }      
  },
  
  show: function( t )
  {
    this.menu.show();
    this.prev = this.target;
    this.target = t;
  },
  
  hide: function()
  {
    this.menu.hide();
//    this.target = null;
  },
  
  setMode: function( m )
  {
    if( ! m )
    {
      this.items[0].show();
      this.items[1].hide();
      this.items[2].hide();
      this.items[3].show();
      this.items[4].show();
    }
    else
    {
      this.items[0].hide();
      this.items[1].show();
      this.items[2].show();
      this.items[3].show();
      this.items[4].show();
    }
  }
}
